import concurrent.futures
import threading
from typing import Callable, List, Dict

class ParallelProcessor:
    def __init__(self, max_workers: int = 5):
        self.max_workers = max_workers
        self.semaphore = threading.Semaphore(max_workers)

    def process_videos_parallel(self, video_paths: List[str], worker: Callable[[str], Dict]):
        results = {}
        failed = []
        with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            futures = {executor.submit(self._run, worker, p): p for p in video_paths}
            for fut in concurrent.futures.as_completed(futures):
                path = futures[fut]
                try:
                    res = fut.result()
                    if res is None:
                        failed.append(path)
                    else:
                        results[path] = res
                except Exception:
                    failed.append(path)
        return {"success": results, "failed": failed}

    def _run(self, worker: Callable[[str], Dict], path: str):
        with self.semaphore:
            return worker(path)
